#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include "pw_pbl/Function.hpp"

struct AddrRange
{
	const std::byte* start;
	const std::byte* limit;

	inline bool operator==(const AddrRange& oth) const noexcept {return start == oth.start && limit == oth.limit;}
	inline bool operator<=(const AddrRange& oth) const noexcept {return start >= oth.start && limit <= oth.limit;}
	inline bool operator>=(const AddrRange& oth) const noexcept {return oth <= *this;}
	inline bool operator<<=(const AddrRange& oth) const noexcept {return start > oth.start && limit == oth.limit;}
	inline bool operator>>=(const AddrRange& oth) const noexcept {return start == oth.start && limit < oth.limit;}
};

std::ostream& operator<< (std::ostream& os, const AddrRange& sta)
{
	return os << "[" << sta.start << ", " << sta.limit << ")";
}

template<typename R, typename ...P>
class pw_pbl::_function::CTester<R(P...)>
{
public:
	using TFunc = R(P...);

	template<typename A, typename B>
	static auto AddrDiff(A* a, B* b){return reinterpret_cast<const std::byte*>(b) - reinterpret_cast<const std::byte*>(a);}

	template<typename S>
	static auto& log(S& os, const pw_pbl::Function<TFunc>& func)
	{
		os << "\n{FunctionInterface";
		os << "\n\tEIsReturnTypeDefaultConstructible=" << func.EIsReturnTypeDefaultConstructible;
		auto* pvt = func.pVTable();
		os << "\n\tpVTable()=" << pvt;
		if(pvt)
		{
			os << "\n\tVTable={cSize=" << pvt->cSize;
			os << " cAlignMark=" << pvt->cAlignMark;
			os << " Call=" << reinterpret_cast<void*>(pvt->Call);
			os << " ConstCall=" << reinterpret_cast<void*>(pvt->ConstCall);
			os << " CopyConstructTo=" << reinterpret_cast<void*>(pvt->CopyConstructTo);
			os << " MoveConstructTo=" << reinterpret_cast<void*>(pvt->MoveConstructTo);
			os << " Destruct=" << reinterpret_cast<void*>(pvt->Destruct);
			os << '}';
		}
		os << "\n\tthis=" << &func;
		os << "\n\tpBuf()=" << func.pBuf();
		os << "\n\tpBuf()-this=" << AddrDiff(&func, func.pBuf());
		if(pvt)
		{
			os << "\n\tsObj()=" << func.sObj();
			os << "\n\tsObj()-pBuf()=" << AddrDiff(func.pBuf(), func.sObj());
			os << "\n\tsObj()+pVTable()->cSize=" << reinterpret_cast<const std::byte*>(func.sObj()) + pvt->cSize;
			os << "\n\tsObj()&pVTable()->cAlignMark=" << (reinterpret_cast<uintptr_t>(func.sObj()) & pvt->cAlignMark);
		}
		os << "\n}";
		return os;
	}

	template<typename S, std::size_t BS>
	static auto& log(S& os, const pw_pbl::Function<TFunc, BS>& func)
	{
		log(os, static_cast<const pw_pbl::Function<TFunc>&>(func));
		os << "{Function";
		os << "\n\tSizeTParm=" << BS;
		os << "\n\tEBufSize=" << func.EBufSize;
		os << "\n\tECellCount=" << func.ECellCount;
		os << "\n\tEExpectedSize=" << func.EExpectedSize;
		os << "\n\t&mBuf=" << &func.mBuf;
		os << "\n\t&mBuf[ECellCount]=" << &func.mBuf[func.ECellCount];
		os << "\n\tsizeof(mBuf)=" << sizeof(func.mBuf);
		os << "\n\tthis+sizeof(*this)=" << reinterpret_cast<const std::byte*>(&func) + sizeof(func);
		os << "\n}";
		return os;
	}
};

namespace pw_pbl {

template<typename F, auto ... BS>
auto& operator<< (std::ostream& os, const Function<F, BS...>& func)
{
	return _function::CTester<F>::log(os, func);
}

template<typename F, auto ... BS>
auto& operator<< (std::ostream& os, const FunctionEx<F, BS...>& func)
{
	return operator<<(os, static_cast<const Function<F, BS...>&>(func));
}

}

struct STFOState{
	std::size_t ID;
	std::size_t SrcID;
	bool IsMoved;

	bool operator==(const STFOState& oth) const
	{
		return ID == oth.ID && SrcID == oth.SrcID && IsMoved == oth.IsMoved;
	}
};

std::ostream& operator<< (std::ostream& os, const STFOState& sta)
{
	return os << std::boolalpha << "{.ID = " << sta.ID << ", .SrcID = " << sta.SrcID << ", .IsMoved = " << sta.IsMoved << "}";
}

class CTestFuncObj
{
	static thread_local std::size_t GID;
	STFOState mState;
public:
	static thread_local std::size_t LastDestoryedID;

	CTestFuncObj(void) :			mState{.ID = ++GID, .SrcID = 0, .IsMoved = false} {}

	CTestFuncObj(const CTestFuncObj& src) : mState{.ID = ++GID, .SrcID = src.mState.ID, .IsMoved = false} {}

	CTestFuncObj(CTestFuncObj&& src) :	mState{.ID = ++GID, .SrcID = src.mState.ID, .IsMoved = true} {}

	~CTestFuncObj(void){LastDestoryedID = mState.ID; mState.ID = 0;}

	const STFOState& operator()(void) const {return mState;}

	static void Reset(void){GID = 0; LastDestoryedID = 0;}
};

thread_local std::size_t CTestFuncObj::GID = 0;
thread_local std::size_t CTestFuncObj::LastDestoryedID = 0;

TEST_CASE("Function"){
	SUBCASE("construct"){
		pw_pbl::Function a = [](int a){return a + 1;};
		REQUIRE(a);
		CHECK(sizeof(a) == a.EExpectedSize);
		CHECK(a(0) == 1);
		CHECK(a(1) == 2);
		CHECK(a(a(2)) == 4);
		SUBCASE("lambda")
		{
			pw_pbl::Function b = [&a](int b){return a(b);};
			REQUIRE(b);
			CHECK(sizeof(b) == b.EExpectedSize);
			CHECK(b(0) == 1);
			CHECK(b(1) == 2);
			CHECK(b(b(2)) == 4);
			pw_pbl::Function c = [a](int c){return a ? a(c) : -1;};
			REQUIRE(c);
			CHECK(sizeof(c) == c.EExpectedSize);
			CHECK(c(0) == 1);
			CHECK(c(1) == 2);
			CHECK(c(c(2)) == 4);
		}
		SUBCASE("rawfunc"){
			int(*func)(int) = [](int a){return a * a;};
			pw_pbl::Function a = func;
			REQUIRE(a);
			REQUIRE(sizeof(a) == a.EExpectedSize);
			CHECK(a(-1) == 1);
			CHECK(a(0) == 0);
			CHECK(a(1) == 1);
			CHECK(a(2) == 4);
		}
		SUBCASE("TestFuncObj"){
			CTestFuncObj::Reset();
			pw_pbl::Function a = CTestFuncObj{};
			REQUIRE(a);
			CHECK(a() == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
			SUBCASE("copy"){
				CTestFuncObj::Reset();
				pw_pbl::Function a = CTestFuncObj{};
				pw_pbl::Function b = a;
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = false});
			}
			SUBCASE("move"){
				CTestFuncObj::Reset();
				pw_pbl::Function a = CTestFuncObj{};
				pw_pbl::Function b = std::move(a);
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = true});
			}
		}
	}
	SUBCASE("operator="){
		pw_pbl::Function<int(int), 1> a;
		a = [](int a){return a + 1;};
		REQUIRE(a);
		CHECK(sizeof(a) == a.EExpectedSize);
		CHECK(a(0) == 1);
		CHECK(a(1) == 2);
		CHECK(a(a(2)) == 4);
		SUBCASE("lambda"){
			pw_pbl::Function<int(int), 1> b;
			b = [&a](int b){return a(b);};
			REQUIRE(b);
			CHECK(sizeof(b) == b.EExpectedSize);
			CHECK(b(0) == 1);
			CHECK(b(1) == 2);
			CHECK(b(b(2)) == 4);
			pw_pbl::Function<int(int), sizeof(a)> c;
			c = [a](int c){return a ? a(c) : -1;};
			REQUIRE(c);
			CHECK(sizeof(c) == c.EExpectedSize);
			CHECK(c(0) == 1);
			CHECK(c(1) == 2);
			CHECK(c(c(2)) == 4);
		}
		SUBCASE("rawfunc"){
			int(*func)(int) = [](int a){return a * a;};
			pw_pbl::Function<int(int), 1> a;
			a = func;
			REQUIRE(a);
			REQUIRE(sizeof(a) == a.EExpectedSize);
			CHECK(a(-1) == 1);
			CHECK(a(0) == 0);
			CHECK(a(1) == 1);
			CHECK(a(2) == 4);
		}
		SUBCASE("TestFuncObj"){
			CTestFuncObj::Reset();
			pw_pbl::Function<const STFOState&(void), sizeof(CTestFuncObj)> a;
			a = CTestFuncObj{};
			REQUIRE(a);
			CHECK(a() == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
			SUBCASE("copy"){
				CTestFuncObj::Reset();
				pw_pbl::Function a = CTestFuncObj{};
				pw_pbl::Function<const STFOState&(void), sizeof(CTestFuncObj)> b;
				b = a;
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = false});
			}
			SUBCASE("move"){
				CTestFuncObj::Reset();
				pw_pbl::Function a = CTestFuncObj{};
				pw_pbl::Function<const STFOState&(void), sizeof(CTestFuncObj)> b;
				b = std::move(a);
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = true});
			}
		}
		a = {};
		REQUIRE_FALSE(a);
	}
	SUBCASE("destruct"){
		CTestFuncObj::Reset();
		pw_pbl::Function a = CTestFuncObj();
		REQUIRE(a);
		CHECK(CTestFuncObj::LastDestoryedID == 1);
		auto& b = a();
		CHECK(b == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
		auto m = CTestFuncObj{};
		a = m;
		REQUIRE(a);
		CHECK(a() == STFOState{.ID = 4, .SrcID = 3, .IsMoved = false});
		CHECK(CTestFuncObj::LastDestoryedID == 2);
		{
			pw_pbl::Function c = CTestFuncObj{};
			REQUIRE(c);
			CHECK(CTestFuncObj::LastDestoryedID == 5);
			CHECK(c() == STFOState{.ID = 6, .SrcID = 5, .IsMoved = true});
		}
		CHECK(CTestFuncObj::LastDestoryedID == 6);
	}
	SUBCASE("operator()"){
		SUBCASE("const overload"){
			struct CConstOverload {
				int mCallState = 0;
				int operator()(int v){mCallState += v; return mCallState;}
				int operator()(int) const {return mCallState;}
			};
			pw_pbl::Function<int(int), 1> a = CConstOverload{};
			const auto& b = a;
			REQUIRE(bool{a});
			REQUIRE(bool{b});
			CHECK(b(9) == 0);
			CHECK(b(-1) == 0);
			CHECK(a(2) == 2);
			CHECK(a(2) == 4);
			CHECK(b(99) == 4);
			CHECK(b(23432) == 4);
		}
		SUBCASE("non const"){
			struct CNonConst {
				int mCallState = 0;
				int operator()(int v){mCallState += v; return mCallState;}
			};
			pw_pbl::Function a = CNonConst{};
			const auto& b = a;
			REQUIRE(bool{a});
			CHECK_FALSE(bool{b});
			CHECK(a(3) == 3);
			CHECK(a(3) == 6);
			CHECK(a(8) == 14);
		}
		SUBCASE("const"){
			struct CConst {
				int& mCallState;
				int operator()(int v) const {return mCallState + v;}
			};
			int m = 0;
			pw_pbl::Function a = CConst{m};
			const auto& b = a;
			REQUIRE(bool{a});
			REQUIRE(bool{b});
			CHECK(b(3) == 3);
			m = 3;
			CHECK(a(3) == 6);
			CHECK(b(4) == 7);
			m = 11;
			CHECK(a(9) == 20);
			CHECK(b(32) == 43);
		}
	}
	SUBCASE("memory layout"){
		struct alignas(32) CLayout {
			uint8_t mCallState = 0;
			int operator()(int)const{return mCallState;}
		};
		auto a = CLayout{};
		pw_pbl::Function b = a;
		REQUIRE(b);
		MESSAGE(b);
	}
}

TEST_CASE("FunctionForward"){
	CTestFuncObj::Reset();
	pw_pbl::Function<const STFOState&(void), pw_pbl::FunctionCellCountFor<CTestFuncObj>()> a;
	using Forwarder = decltype(a)::Forwarder;
	auto b = [&a](Forwarder f){a = f;};
	b(CTestFuncObj{});
	REQUIRE(a);
	CHECK(a() == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
	auto c = CTestFuncObj{};
	b(c);
	REQUIRE(a);
	CHECK(a() == STFOState{.ID = 4, .SrcID = 3, .IsMoved = false});
	Forwarder d = a;
	pw_pbl::Function<const STFOState&(void), pw_pbl::FunctionCellCountFor<CTestFuncObj>()> e = d;
	REQUIRE(e);
	CHECK(e() == STFOState{.ID = 5, .SrcID = 4, .IsMoved = false});
	REQUIRE(d);
	Forwarder::TCell buf[5];
	auto* p = d.ContructTo(buf);
	REQUIRE(p);
	REQUIRE(reinterpret_cast<void*>(p) == reinterpret_cast<void*>(buf));
	REQUIRE(*p);
	CHECK((*p)() == STFOState{.ID = 6, .SrcID = 4, .IsMoved = false});
}

TEST_CASE("FunctionRef"){
	SUBCASE("construct"){
		SUBCASE("lambda"){
			auto a = [a = 1](int v)mutable{return a *= v;};
			pw_pbl::FunctionRef ref = a;
			CHECK(ref(3) == 3);
			CHECK(ref(3) == 9);
			CHECK(ref(4) == 36);
		}
		SUBCASE("rawfunc"){
			int(*pfunc)(int) = [](int v){static int a = 2; return a *= v;};
			pw_pbl::FunctionRef ref = pfunc;
			CHECK(ref(3) == 6);
			CHECK(ref(3) == 18);
			CHECK(ref(4) == 72);
		}
		SUBCASE("CTestFuncObj"){
			CTestFuncObj::Reset();
			auto a = CTestFuncObj{};
			pw_pbl::FunctionRef b = a;
			CHECK(b() == STFOState{.ID = 1, .SrcID = 0, .IsMoved = false});
			auto c = a;
			b = c;
			CHECK(b() == STFOState{.ID = 2, .SrcID = 1, .IsMoved = false});
		}
		SUBCASE("Function"){
			pw_pbl::Function func = [a = 3](int v){return a * v;};
			pw_pbl::FunctionRef ref = func.FastRef_X();
			REQUIRE(ref);
			CHECK(ref(1) == 3);
			CHECK(ref(2) == 6);
			const pw_pbl::Function b = [a=0](int v)mutable{return a+=v;};
			REQUIRE_FALSE(bool{b});
			pw_pbl::Function c = [a=0](int v)mutable{return a+=v;};
			REQUIRE(bool{c});
			ref = c.FastRef_X();
			CHECK(ref(3) == 3);
			CHECK(ref(3) == 6);
			CHECK(ref(7) == 13);
		}
	}
}

TEST_CASE("FunctionStorage"){
	pw_pbl::FunctionStorage::SBuf<20> buf;
	pw_pbl::FunctionStorage const csto {buf};
	CTestFuncObj::Reset();
	auto ptr = csto.Construct(CTestFuncObj{});
	CHECK(CTestFuncObj::LastDestoryedID == 1);
	REQUIRE(csto);
	REQUIRE(ptr);
	CHECK(ptr() == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
	ptr.reset(nullptr);
	CHECK_FALSE(ptr);
	CHECK(CTestFuncObj::LastDestoryedID == 2);
	{
		auto sto = csto;
		auto mm = CTestFuncObj{};
		sto.Construct(mm);
		CHECK(CTestFuncObj::LastDestoryedID == 4);
		REQUIRE_FALSE(sto);
	}
	CHECK(CTestFuncObj::LastDestoryedID == 3);
	{
		auto sto = csto;
		auto ptr = sto.SliceOutAndConstruct(CTestFuncObj{});
		REQUIRE(sto);
		REQUIRE(ptr);
		CHECK(CTestFuncObj::LastDestoryedID == 5);
		CHECK(ptr() == STFOState{.ID = 6, .SrcID = 5, .IsMoved = true});
		CHECK((AddrRange{sto.test_get_start_addr(), sto.test_get_limit_addr()} >>= AddrRange{csto.test_get_start_addr(), csto.test_get_limit_addr()}));
		CHECK((AddrRange{ptr->test_get_start_addr(), ptr->test_get_limit_addr()} <<= AddrRange{csto.test_get_start_addr(), csto.test_get_limit_addr()}));
	}
}

TEST_CASE("FunctionEx"){
	SUBCASE("construct"){
		pw_pbl::FunctionEx a = [](int a){return a + 1;};
		REQUIRE(a);
		CHECK(sizeof(a) == a.EExpectedSize);
		CHECK(a(0) == 1);
		CHECK(a(1) == 2);
		CHECK(a(a(2)) == 4);
		SUBCASE("lambda")
		{
			pw_pbl::FunctionEx b = [&a](int b){return a(b);};
			REQUIRE(b);
			CHECK(sizeof(b) == b.EExpectedSize);
			CHECK(b(0) == 1);
			CHECK(b(1) == 2);
			CHECK(b(b(2)) == 4);
			pw_pbl::FunctionEx c = [a](int c){return a ? a(c) : -1;};
			REQUIRE(c);
			CHECK(sizeof(c) == c.EExpectedSize);
			CHECK(c(0) == 1);
			CHECK(c(1) == 2);
			CHECK(c(c(2)) == 4);
		}
		SUBCASE("rawfunc"){
			int(*func)(int) = [](int a){return a * a;};
			pw_pbl::FunctionEx a = func;
			REQUIRE(a);
			REQUIRE(sizeof(a) == a.EExpectedSize);
			CHECK(a(-1) == 1);
			CHECK(a(0) == 0);
			CHECK(a(1) == 1);
			CHECK(a(2) == 4);
		}
		SUBCASE("TestFuncObj"){
			CTestFuncObj::Reset();
			pw_pbl::FunctionEx a = CTestFuncObj{};
			REQUIRE(a);
			CHECK(a() == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
			SUBCASE("copy"){
				CTestFuncObj::Reset();
				pw_pbl::FunctionEx a = CTestFuncObj{};
				pw_pbl::FunctionEx b = a;
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = false});
			}
			SUBCASE("move"){
				CTestFuncObj::Reset();
				pw_pbl::FunctionEx a = CTestFuncObj{};
				pw_pbl::FunctionEx b = std::move(a);
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = true});
			}
		}
	}
	SUBCASE("operator="){
		pw_pbl::FunctionEx<int(int), 1> a;
		a = [](int a){return a + 1;};
		REQUIRE(a);
		CHECK(sizeof(a) == a.EExpectedSize);
		CHECK(a(0) == 1);
		CHECK(a(1) == 2);
		CHECK(a(a(2)) == 4);
		SUBCASE("lambda"){
			pw_pbl::FunctionEx<int(int), 1> b;
			b = [&a](int b){return a(b);};
			REQUIRE(b);
			CHECK(sizeof(b) == b.EExpectedSize);
			CHECK(b(0) == 1);
			CHECK(b(1) == 2);
			CHECK(b(b(2)) == 4);
			pw_pbl::FunctionEx<int(int), pw_pbl::FunctionCellCountFor(a)> c;
			c = [a](int c){return a ? a(c) : -1;};
			REQUIRE(c);
			CHECK(sizeof(c) == c.EExpectedSize);
			CHECK(c(0) == 1);
			CHECK(c(1) == 2);
			CHECK(c(c(2)) == 4);
		}
		SUBCASE("rawfunc"){
			int(*func)(int) = [](int a){return a * a;};
			pw_pbl::FunctionEx<int(int), 1> a;
			a = func;
			REQUIRE(a);
			REQUIRE(sizeof(a) == a.EExpectedSize);
			CHECK(a(-1) == 1);
			CHECK(a(0) == 0);
			CHECK(a(1) == 1);
			CHECK(a(2) == 4);
		}
		SUBCASE("TestFuncObj"){
			CTestFuncObj::Reset();
			pw_pbl::FunctionEx<const STFOState&(void), pw_pbl::FunctionCellCountFor<CTestFuncObj>()> a;
			a = CTestFuncObj{};
			REQUIRE(a);
			CHECK(a() == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
			SUBCASE("copy"){
				CTestFuncObj::Reset();
				pw_pbl::FunctionEx a = CTestFuncObj{};
				pw_pbl::FunctionEx<const STFOState&(void), pw_pbl::FunctionCellCountFor<CTestFuncObj>()> b;
				b = a;
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = false});
			}
			SUBCASE("move"){
				CTestFuncObj::Reset();
				pw_pbl::FunctionEx a = CTestFuncObj{};
				pw_pbl::FunctionEx<const STFOState&(void), pw_pbl::FunctionCellCountFor<CTestFuncObj>()> b;
				b = std::move(a);
				REQUIRE(b);
				CHECK(b() == STFOState{.ID = 3, .SrcID = 2, .IsMoved = true});
			}
		}
		a = {};
		REQUIRE_FALSE(a);
	}
	SUBCASE("destruct"){
		CTestFuncObj::Reset();
		pw_pbl::FunctionEx a = CTestFuncObj();
		REQUIRE(a);
		CHECK(CTestFuncObj::LastDestoryedID == 1);
		auto& b = a();
		CHECK(b == STFOState{.ID = 2, .SrcID = 1, .IsMoved = true});
		auto m = CTestFuncObj{};
		a = m;
		REQUIRE(a);
		CHECK(a() == STFOState{.ID = 4, .SrcID = 3, .IsMoved = false});
		CHECK(CTestFuncObj::LastDestoryedID == 2);
		{
			pw_pbl::FunctionEx c = CTestFuncObj{};
			REQUIRE(c);
			CHECK(CTestFuncObj::LastDestoryedID == 5);
			CHECK(c() == STFOState{.ID = 6, .SrcID = 5, .IsMoved = true});
		}
		CHECK(CTestFuncObj::LastDestoryedID == 6);
	}
	SUBCASE("operator()"){
		SUBCASE("const overload"){
			struct CConstOverload {
				int mCallState = 0;
				int operator()(int v){mCallState += v; return mCallState;}
				int operator()(int) const {return mCallState;}
			};
			pw_pbl::FunctionEx<int(int), 1> a = CConstOverload{};
			const auto& b = a;
			REQUIRE(bool{a});
			REQUIRE(bool{b});
			CHECK(b(9) == 0);
			CHECK(b(-1) == 0);
			CHECK(a(2) == 2);
			CHECK(a(2) == 4);
			CHECK(b(99) == 4);
			CHECK(b(23432) == 4);
		}
		SUBCASE("non const"){
			struct CNonConst {
				int mCallState = 0;
				int operator()(int v){mCallState += v; return mCallState;}
			};
			pw_pbl::FunctionEx a = CNonConst{};
			const auto& b = a;
			REQUIRE(bool{a});
			CHECK_FALSE(bool{b});
			CHECK(a(3) == 3);
			CHECK(a(3) == 6);
			CHECK(a(8) == 14);
		}
		SUBCASE("const"){
			struct CConst {
				int& mCallState;
				int operator()(int v) const {return mCallState + v;}
			};
			int m = 0;
			pw_pbl::FunctionEx a = CConst{m};
			const auto& b = a;
			REQUIRE(bool{a});
			REQUIRE(bool{b});
			CHECK(b(3) == 3);
			m = 3;
			CHECK(a(3) == 6);
			CHECK(b(4) == 7);
			m = 11;
			CHECK(a(9) == 20);
			CHECK(b(32) == 43);
		}
	}
	SUBCASE("memory layout"){
		struct alignas(32) CLayout {
			uint8_t mCallState = 0;
			int operator()(int)const{return mCallState;}
		};
		auto a = CLayout{};
		pw_pbl::FunctionEx b = a;
		REQUIRE(b);
		MESSAGE(b);
	}
}
